package com.yzycoc.hamster.demo.time202507.image;
import cn.hutool.core.io.FileUtil;
import net.coobird.thumbnailator.Thumbnails;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

/**
 * 压缩图片
 */
public class BatchImageCompressor {

    // ============= 全局配置参数 =============
    // 源目录路径
    private static final String SOURCE_DIR = "E:\\system\\Pictures\\压缩\\start";
    // 输出目录路径
    private static final String TARGET_DIR = "E:\\system\\Pictures\\压缩\\start_压缩后";
    // 压缩模式：SIZE_MODE(按目标大小) | PARAM_MODE(按参数压缩)
    private static final CompressMode MODE = CompressMode.SIZE_MODE;

    // 按目标大小压缩的参数
    private static final long TARGET_SIZE_KB = 296; // 目标大小(KB)

    // 按参数压缩的参数
    private static final Double SCALE = 0.5;       // 缩放比例(0-1), null表示不缩放
    private static final Double QUALITY = 0.8;     // 压缩质量(0-1), null表示不设置质量
    private static final String OUTPUT_FORMAT = "jpg"; // 输出格式, null表示保持原格式
    // ======================================

    public static void main(String[] args) {
        // 确保输出目录存在
        FileUtil.mkdir(TARGET_DIR);

        // 获取源目录下所有图片文件
        List<File> imageFiles = FileUtil.loopFiles(SOURCE_DIR,
                pathname -> pathname.isFile() && isImageFile(pathname));

        if (imageFiles.isEmpty()) {
            System.out.println("源目录中没有找到图片文件: " + SOURCE_DIR);
            return;
        }

        System.out.println("开始批量压缩图片，共" + imageFiles.size() + "张...");

        int successCount = 0;
        for (File sourceFile : imageFiles) {
            try {
                String relativePath = FileUtil.subPath(SOURCE_DIR, sourceFile);
                String targetPath = FileUtil.normalize(TARGET_DIR + "/" + relativePath);

                // 确保子目录存在
                FileUtil.mkdir(FileUtil.file(targetPath).getParentFile());

                // 根据模式选择压缩方式
                if (MODE == CompressMode.SIZE_MODE) {
                    compressToTargetSize(sourceFile.getPath(), targetPath, TARGET_SIZE_KB, OUTPUT_FORMAT);
                } else {
                    compressWithParams(sourceFile.getPath(), targetPath, SCALE, QUALITY, OUTPUT_FORMAT);
                }

                successCount++;
                System.out.println("压缩成功: " + relativePath + " → " +
                        FileUtil.file(targetPath).length() / 1024 + "KB");
            } catch (Exception e) {
                System.err.println("压缩失败: " + sourceFile.getName() + " - " + e.getMessage());
            }
        }

        System.out.println("批量压缩完成! 成功: " + successCount + "/" + imageFiles.size());
    }

    private static boolean isImageFile(File file) {
        String name = file.getName().toLowerCase();
        return name.endsWith(".jpg") || name.endsWith(".jpeg") ||
                name.endsWith(".png") || name.endsWith(".bmp") ||
                name.endsWith(".gif");
    }

    private static void compressWithParams(String sourcePath, String targetPath,
                                           Double scale, Double quality, String format) throws IOException {
        Thumbnails.Builder<File> builder = Thumbnails.of(sourcePath);

        if (scale != null) builder.scale(scale);
        if (quality != null) builder.outputQuality(quality);

        String outputFormat = format != null ? format : getFormatName(new File(sourcePath));
        builder.outputFormat(outputFormat).toFile(targetPath);
    }

    private static void compressToTargetSize(String sourcePath, String targetPath,
                                             long targetSizeKB, String format) throws IOException {
        long targetSizeBytes = targetSizeKB * 1024;
        File sourceFile = new File(sourcePath);
        File targetFile = new File(targetPath);

        // 初始参数
        double quality = 0.9;
        double scale = 1.0;
        int maxAttempts = 20; // 最大尝试次数
        int attempts = 0;
        long fileSize = Long.MAX_VALUE;

        // 读取原始图片信息
        BufferedImage image = ImageIO.read(sourceFile);
        int originalWidth = image.getWidth();
        int originalHeight = image.getHeight();

        // 最大允许尺寸（适合手机浏览）
        int maxWidth = 1920;
        int maxHeight = 1080;

        // 先检查是否需要缩小尺寸
        if (originalWidth > maxWidth || originalHeight > maxHeight) {
            scale = Math.min((double)maxWidth / originalWidth, (double)maxHeight / originalHeight);
        }

        // 迭代压缩过程
        while (fileSize > targetSizeBytes && attempts < maxAttempts) {
            // 逐步降低质量和尺寸
            if (attempts > 5) {
                // 如果多次尝试后仍达不到目标，开始更激进地缩小尺寸
                scale *= 0.9;
            }

            if (attempts > 10) {
                // 如果仍然太大，进一步降低质量
                quality = Math.max(0.3, quality - 0.05);
            }

            // 确保尺寸不小于最小值
            int width = Math.max((int)(originalWidth * scale), 100);
            int height = Math.max((int)(originalHeight * scale), 100);

            // 执行压缩
            Thumbnails.of(sourceFile)
                    .size(width, height)
                    .outputQuality(quality)
                    .outputFormat(format != null ? format : getFormatName(sourceFile))
                    .toFile(targetFile);

            fileSize = targetFile.length();
            attempts++;

            // 如果接近目标大小，微调质量
            if (fileSize > targetSizeBytes * 0.9 && fileSize < targetSizeBytes * 1.5) {
                quality = Math.max(0.1, quality - 0.02);
            }
        }

        // 如果仍然大于目标大小，使用更激进的方法
        if (fileSize > targetSizeBytes) {
            // 计算需要缩小的比例
            double sizeRatio = (double)targetSizeBytes / fileSize;
            scale *= Math.sqrt(sizeRatio);

            int finalWidth = Math.max((int)(originalWidth * scale), 100);
            int finalHeight = Math.max((int)(originalHeight * scale), 100);

            Thumbnails.of(sourceFile)
                    .size(finalWidth, finalHeight)
                    .outputQuality(0.3) // 使用较低质量
                    .outputFormat(format != null ? format : getFormatName(sourceFile))
                    .toFile(targetFile);
        }
    }


    private static String getFormatName(File file) {
        String fileName = file.getName();
        int dotIndex = fileName.lastIndexOf('.');
        return dotIndex > 0 ? fileName.substring(dotIndex + 1) : "jpg";
    }

    private enum CompressMode {
        SIZE_MODE,  // 按目标大小压缩
        PARAM_MODE   // 按参数压缩
    }
}